package com.alibaba.citrus.cr.platform.enhance.facade.service.inventoryAllot;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

import com.alibaba.citrus.cr.common.annotation.EpochTransactional;
import com.alibaba.citrus.cr.common.annotation.FacadeInvoker;
import com.alibaba.citrus.cr.common.exception.FacadeException;
import com.alibaba.citrus.cr.common.exception.FunctionException;
import com.alibaba.citrus.cr.platform.enhance.functions.inventoryAllot.entity.InventoryAllotLineEntity;
import com.alibaba.citrus.cr.platform.enhance.functions.inventoryAllot.factory.InventoryAllotLineFactory;
import com.alibaba.citrus.cr.platform.enhance.repository.InventoryAllotLineRepository;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.fastjson.JSON;
import com.alibaba.lattice2.epoch.middleware.cache.runtime.service.EpochCacheService;
import com.alibaba.lattice2.epoch.sdk.model.Result;

import com.epoch.app.crforecastsales.sdo.ForecastOrderLineSDO;
import com.epoch.app.crplatformenhance.inventoryallotlinewrite.dto.ConsumerForecastOrderRefuseRequest;
import com.epoch.app.crplatformenhance.inventoryallotlinewrite.dto.ReleaseAndDeductRequest;
import com.epoch.app.crplatformenhance.inventoryallotlinewrite.service.InventoryAllotLineWriteService;
import com.epoch.app.crplatformenhance.inventoryallotquery.service.InventoryAllotQueryService;
import com.epoch.app.crplatformenhance.model.dto.*;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;

@Service
@Primary
public class InventoryAllotLineServiceImpl implements InventoryAllotLineWriteService {
    @Resource
    private InventoryAllotQueryService inventoryAllotQueryService;
    @Resource
    private InventoryAllotLineRepository inventoryAllotLineRepository;
    @Resource
    private EpochCacheService epochCacheService;
    public static final String ALLOTORDERLINE_REDIS_CATCH_CODE = "REDIS_CACHE";

    private static final Log log = Log.getLogger(InventoryAllotLineServiceImpl.class);


    @Override
    public Result<Boolean> updateRemainingQuantity(UpdateRemainingQuantityRequest updateRemainingQuantityRequest) {
        InventoryAllotLineEntity inventoryAllotLineEntity = InventoryAllotLineFactory.updateRemainingQuantity(
                updateRemainingQuantityRequest);
        inventoryAllotLineEntity.updateRemainingQuantity();
        return Result.success(true);
    }

    @Override
    @FacadeInvoker
    public Result<DailyInventoryDeductResponse> queryAndDeduct(QueryAllotAndDeductRequest queryAllotAndDeductRequest) {
        QueryAllotRequest queryAllotRequest = new QueryAllotRequest();

        BeanUtils.copyProperties(queryAllotAndDeductRequest, queryAllotRequest);
        DailyInventoryDeductResponse deductResponse = new DailyInventoryDeductResponse();
//        deductResponse.setRealDeductQuantity("0");
        Result<QueryAllotResponse> resp = inventoryAllotQueryService.queryAllot(queryAllotRequest);
        if (resp == null || resp.getResult() == null) {
            return Result.fail("OTS-06-005-00-15-007", "未查询到分解单数据，每日库存扣减失败");
        }
        BigDecimal remainingQuantity = new BigDecimal(resp.getResult().getRemainingQuantity());
        BigDecimal readyDeduct = new BigDecimal(queryAllotAndDeductRequest.getDeductQuantity()).setScale(3,
                RoundingMode.DOWN);
        //add my myw,每日库存分解开启了限量以后，提报数量不能大于剩余每日库存分解量，强制控制，抛出异常
        if (resp.getResult().getMainLimitSwitch()) {
            if (readyDeduct.compareTo(remainingQuantity)>0){
                throw new FunctionException("OTS-06-005-00-15-022","已开启每日分解库存限量,提报量不能大于每日分解库存剩余量!");
            }
        }
        BigDecimal realDeduct = remainingQuantity.min(readyDeduct).setScale(3, RoundingMode.DOWN);

        UpdateAllotLineRequest updateRequest = new UpdateAllotLineRequest();
        updateRequest.setId(resp.getResult().getId());
        updateRequest.setRemainingQuantity(remainingQuantity.subtract(realDeduct).setScale(3, RoundingMode.DOWN)
                .toString());
        updateRequest.setSyncVersion(resp.getResult().getSyncVersion());

        Integer updateCount = inventoryAllotLineRepository.updateRemainingQuantity(updateRequest);
        if (updateCount == null || updateCount == 0) {
            log.info("数据已被更新，每日库存扣减失败! " + JSON.toJSONString(queryAllotAndDeductRequest));
            return Result.fail("OTS-06-005-00-15-008", "数据已被更新，每日库存扣减失败，请重试");
        }
        deductResponse.setRealDeductQuantity(realDeduct.toString());
        deductResponse.setAllotLineId(updateRequest.getId());
        return Result.success(deductResponse);
    }

    @FacadeInvoker
    @Override
    public Result<Boolean> updateDistributionQuantity(
            UpdateDistributionQuantityRequest updateDistributionQuantityRequest) {

        InventoryAllotLineEntity inventoryAllotLineEntity = InventoryAllotLineFactory.updateDistributionQuantity(
                updateDistributionQuantityRequest);
        inventoryAllotLineEntity.updateDistributionQuantity();
        return Result.success(true);
    }

    @Override
    public Result<Boolean> reverseAllotLine(ReverseAllotLineRequest reverseAllotLineRequest){
        String allotLineId = reverseAllotLineRequest.getAllotLineId();
        BigDecimal oldDeductQuantity = new BigDecimal(reverseAllotLineRequest.getReverseQuantity()).setScale(3,
                RoundingMode.DOWN);
        InventoryAllotLineSDO inventoryAllotLineSDO = inventoryAllotLineRepository.queryById(allotLineId);
        if (inventoryAllotLineSDO == null ) {
            return Result.fail("OTS-06-005-00-15-018", "未查询到分解明细单数据，每日库存释放失败");
        }
        BigDecimal remainingQuantity = new BigDecimal(inventoryAllotLineSDO.getRemainingQuantity());

        UpdateAllotLineRequest releaseUpdateRequest = new UpdateAllotLineRequest();
        releaseUpdateRequest.setId(allotLineId);
        releaseUpdateRequest.setRemainingQuantity(remainingQuantity.add(oldDeductQuantity).setScale(3, RoundingMode.DOWN)
                .toString());
        releaseUpdateRequest.setSyncVersion(inventoryAllotLineSDO.getSyncVersion());

        Integer releaseUpdateCount = inventoryAllotLineRepository.updateRemainingQuantity(releaseUpdateRequest);
        if (releaseUpdateCount == null || releaseUpdateCount == 0) {
            log.info("数据已被更新，每日库存释放失败，请重试! " + JSON.toJSONString(reverseAllotLineRequest));
            return Result.fail("OTS-06-005-00-15-019", "数据已被更新，每日库存释放失败，请重试");
        }
        return Result.success(Boolean.TRUE);
    }


    @Override
    public Result<Boolean> consumerForecastOrderRefuse(ConsumerForecastOrderRefuseRequest messageRequest) {
        log.info("预报订单回滚库存消息:" + messageRequest.getMessage());

        ForecastOrderLineSDO forecastOrderLineSDO = JSON.parseObject(messageRequest.getMessage(), ForecastOrderLineSDO.class);

        String lockKey = "DAILY_" + forecastOrderLineSDO.getId();
        try {
            //幂等
            boolean lock = epochCacheService.setIfAbsent(ALLOTORDERLINE_REDIS_CATCH_CODE, lockKey, "");
            //获取到锁，表明可以新建,获取不到锁，表明是重复请求
            if (!lock) {
                log.info("该预报单行已回补:" + forecastOrderLineSDO.getId());
                return Result.success(null);
            }
            epochCacheService.expire(ALLOTORDERLINE_REDIS_CATCH_CODE, lockKey, 30L, TimeUnit.MINUTES);

            Map feature = forecastOrderLineSDO.getFeatures();
            if (feature != null) {
                String allotlineId = (String) feature.get("allotlineid");
                if (StringUtils.isEmpty(allotlineId) || feature.get("disintegrationQty") == null) {
                    return Result.success(null);
                }
                BigDecimal quantity = new BigDecimal(String.valueOf(feature.get("disintegrationQty")));
                log.info("每日库存回补核心参数: allotlineId = " + allotlineId + " 数量:" + quantity);
                if (StringUtils.isNotEmpty(allotlineId) && quantity != null) {
                    InventoryAllotLineSDO result = this.inventoryAllotLineRepository.queryById(allotlineId);
                    if (result != null) {
                        UpdateAllotLineRequest request = new UpdateAllotLineRequest();
                        request.setId(allotlineId);
                        request.setSyncVersion(result.getSyncVersion());
                        BigDecimal totalCount = new BigDecimal("0");
                        BigDecimal nowCount = new BigDecimal(result.getRemainingQuantity());
                        //                   if(nowCount != null){
                        //                       totalCount.add(nowCount);
                        //                   }
                        BigDecimal res = totalCount.add(nowCount).add(quantity).setScale(3, RoundingMode.DOWN);
                        request.setRemainingQuantity(res.toString());
                        log.info("每日库存回补请求参数:" + JSON.toJSONString(request));
                        Integer updateCount = this.inventoryAllotLineRepository.updateRemainingQuantity(request);
                        log.info("每日库存回补响应参数:" + updateCount);
                        if (updateCount == null || updateCount <= 0) {
                            throw new FacadeException("OTS-06-005-00-15-012");
                        }
                    }
                }
            }
        } catch (Exception e) {
            epochCacheService.remove(ALLOTORDERLINE_REDIS_CATCH_CODE, Lists.newArrayList(lockKey));
            log.error("回补失败", e);
            throw new FacadeException("OTS-06-005-00-15-011");
        }

        return Result.success(true);
    }

    @Override
    @EpochTransactional(appCode="cr_platform_enhance", dataSourceCode = "cr_ots", dataSourceType = "app")
    public Result<DailyInventoryDeductResponse> releaseAndDeduct(ReleaseAndDeductRequest releaseAndDeductRequest){
        String allotLineId = releaseAndDeductRequest.getAllotLineId();
        BigDecimal oldDeductQuantity = new BigDecimal(releaseAndDeductRequest.getOldDeductQuantity()).setScale(3,
                RoundingMode.DOWN);
        BigDecimal newDeductQuantity =new BigDecimal( releaseAndDeductRequest.getNewDeductQuantity()).setScale(3,
                RoundingMode.DOWN);


        DailyInventoryDeductResponse deductResponse = new DailyInventoryDeductResponse();
//        deductResponse.setRealDeductQuantity("0");
        InventoryAllotLineSDO inventoryAllotLineSDO = inventoryAllotLineRepository.queryById(allotLineId);
        if (inventoryAllotLineSDO == null ) {
            throw new FunctionException("OTS-06-005-00-15-014", "Step 1，未查询到分解明细单数据，每日库存释放并扣减失败");
        }
        BigDecimal remainingQuantity = new BigDecimal(inventoryAllotLineSDO.getRemainingQuantity());


        UpdateAllotLineRequest releaseUpdateRequest = new UpdateAllotLineRequest();
        releaseUpdateRequest.setId(allotLineId);
        releaseUpdateRequest.setRemainingQuantity(remainingQuantity.add(oldDeductQuantity).setScale(3, RoundingMode.DOWN)
                .toString());
        releaseUpdateRequest.setSyncVersion(inventoryAllotLineSDO.getSyncVersion());

        Integer releaseUpdateCount = inventoryAllotLineRepository.updateRemainingQuantity(releaseUpdateRequest);
        if (releaseUpdateCount == null || releaseUpdateCount == 0) {
            log.info("数据已被更新，释放并扣减，每日库存释放失败! " + JSON.toJSONString(releaseAndDeductRequest));
            throw new FunctionException("OTS-06-005-00-15-015", "数据已被更新，释放并扣减，每日库存释放失败，请重试");
        }


        InventoryAllotLineSDO leastAllotLine = inventoryAllotLineRepository.queryById(allotLineId);
        if (leastAllotLine == null ) {
            throw new FunctionException("OTS-06-005-00-15-017", "Step 2，未查询到分解明细单数据，每日库存释放并扣减失败");
        }
        //查询主单的 限量开关 信息
        String inventoryAllotId = leastAllotLine.getInventoryAllotId();
        InventoryAllotQueryByIdRequest inventoryAllotQueryByIdRequest = new InventoryAllotQueryByIdRequest();
        inventoryAllotQueryByIdRequest.setId(inventoryAllotId);
        Result<InventoryAllotSDO> inventoryAllotSDOResult = inventoryAllotQueryService.queryById(inventoryAllotQueryByIdRequest);
        if (inventoryAllotSDOResult == null|| inventoryAllotSDOResult.getResult()==null) {
            throw new FunctionException("OTS-06-005-00-15-023", "Step 3，未查询到分解主单数据，每日库存释放并扣减失败");
        }

        BigDecimal leastRemainingQuantity = new BigDecimal(leastAllotLine.getRemainingQuantity()).setScale(3, RoundingMode.DOWN);
        //add my myw,每日库存分解开启了限量以后，提报数量不能大于剩余每日库存分解量
        // ，强制控制，抛出异常
        if (!Objects.isNull(inventoryAllotSDOResult.getResult().getLimitSwitch()) && inventoryAllotSDOResult.getResult().getLimitSwitch()) {
            if (newDeductQuantity.compareTo(leastRemainingQuantity)>0){
                throw new FunctionException("OTS-06-005-00-15-022","已配置每日分解库存限量,提报量不能大于每日分解库存剩余量!");
            }
        }
        BigDecimal realDeduct = leastRemainingQuantity.min(newDeductQuantity).setScale(3, RoundingMode.DOWN);

        UpdateAllotLineRequest updateRequest = new UpdateAllotLineRequest();
        updateRequest.setId(allotLineId);
        updateRequest.setRemainingQuantity(leastRemainingQuantity.subtract(realDeduct).setScale(3, RoundingMode.DOWN)
                .toString());
        updateRequest.setSyncVersion(leastAllotLine.getSyncVersion());

        Integer updateCount = inventoryAllotLineRepository.updateRemainingQuantity(updateRequest);
        if (updateCount == null || updateCount == 0) {
            log.info("数据已被更新，释放并扣减，每日库存扣减失败! " + JSON.toJSONString(releaseAndDeductRequest));
            throw new FunctionException("OTS-06-005-00-15-016", "数据已被更新，释放并扣减，每日库存扣减失败，请重试");
        }
        deductResponse.setRealDeductQuantity(realDeduct.toString());
        deductResponse.setAllotLineId(updateRequest.getId());
        return Result.success(deductResponse);
    }

    @Override
    @EpochTransactional(appCode="cr_platform_enhance", dataSourceCode = "cr_ots", dataSourceType = "app")
    public Result<Boolean> batchRelease(BatchReleaseDailyInvRequest batchReleaseDailyInvRequest){

        if (Objects.isNull(batchReleaseDailyInvRequest)|| CollectionUtils.isEmpty(batchReleaseDailyInvRequest.getReleasesList())){
            return Result.fail("OTS-06-005-00-15-020","释放集合不能为空！");
        }

        for (ReleaseDailyInvRequest releaseDailyInvRequest : batchReleaseDailyInvRequest.getReleasesList()) {
            ReverseAllotLineRequest reverseAllotLineRequest = new ReverseAllotLineRequest();
            reverseAllotLineRequest.setAllotLineId(releaseDailyInvRequest.getAllotLineId());
            reverseAllotLineRequest.setReverseQuantity(releaseDailyInvRequest.getReleaseQuantity());
            Result<Boolean> booleanResult = reverseAllotLine(reverseAllotLineRequest);
            if (Objects.isNull(booleanResult)||!booleanResult.isSuccess()||!booleanResult.getResult()){
                log.error("释放每日库存分解失败!,"+JSON.toJSONString(releaseDailyInvRequest));
                throw new FunctionException("OTS-06-005-00-15-021","释放每日库存分解失败!");
            }
        }
        return Result.success(Boolean.TRUE);
    }

}
